/* 
 * File:   XUDPScaner.cpp
 * Author: minaev
 * 
 * Created on 5 Ноябрь 2013 г., 12:24
 */

#include "XUDPScaner.h"
#include "Xservice.h"
#include "Xmsg.h"

#include <stdio.h>
#include <unistd.h>

XUDPScaner::XUDPScaner(XUDPServ* udpServ, XbeeContainer* xcont) {
    this->udpServ = udpServ;
    this->xcont = xcont;
    this->updShmem = xcont->getUDPShareMem();
    this->workThreadScan = 1;
    /*this->pauseCond->__data.__broadcast_seq=0;
    this->pauseCond->__data.__futex=0;
    this->pauseCond->__data.__lock=0;
    this->pauseCond->__data.__mutex=0;
    this->pauseCond->__data.__nwaiters=0;
    this->pauseCond->__data.__total_seq=0;
    this->pauseCond->__data.__wakeup_seq=0;
    this->pauseCond->__data.__woken_seq=0;*/
}

XUDPScaner::~XUDPScaner() {
    workThreadScan = 0;
    while (workThreadScan == 0) {
        usleep(1000);
    }
    pthread_cond_destroy(&this->pauseCond);
}

void XUDPScaner::startThread() {
    pthread_create(&this->scanUDPThread, NULL,
            XUDPScaner::threadScanerFunc, (void*) this);
}

void XUDPScaner::readUDP() {
    pthread_cond_signal(&this->pauseCond);
}

void* XUDPScaner::threadScanerFunc(void* obj) {
    XUDPScaner* ths = (XUDPScaner*) obj;
    char* msg;
    pthread_mutex_lock(&ths->pauseMutex);
    while (ths->workThreadScan != 0) {
        pthread_cond_wait(&ths->pauseCond, &ths->pauseMutex);

        msg = ths->udpServ->readMsg();
        while (msg != NULL) {
            ths->proccessBuffer(msg, ths->udpServ->readLastLen(),
                    ths->udpServ->readLastIP());
            msg = ths->udpServ->readMsg();
        }
        Xmsg::printf("--OK--\n");
    }
    ths->workThreadScan = 1;
}

/**
 * 
 * @param msg
 * @param lenmsg
 * @return 0-success, else error
 */
int XUDPScaner::proccessBuffer(char* msg, int lenmsg, uint32_t ip) {
    static char* smsg;
    //Xmsg::printf("received len %i: ", lenmsg);
    //Xservice::printArrayToHexStr(msg, lenmsg);
    static uint16_t crc;

    if ((uint8_t) msg[0] != (uint8_t) ((MAGIC_NUM >> 8) & 0xff)
            || (uint8_t) msg[1] != (uint8_t) (MAGIC_NUM & 0xff)) {
        Xmsg::printf("magic: %x\n", *(uint16_t*) msg);
        Xmsg::log("proccessBuffer: bad magic number");
        return 1;
    }
    if (lenmsg < SUM_WITHOUT_DATA) {
        Xmsg::log(2, "proccessBuffer: small packet ", Xservice::itos(lenmsg));
        return 2;
    }
    if (XUDPScaner::getLengthInPack(msg) != lenmsg) {
        Xmsg::log(2, "proccessBuffer: bad len packet ", Xservice::itos(lenmsg));
        return 3;
    }
    if (*(uint16_t*) (msg + lenmsg - 2) != (crc = XUDPShareMem::getCRC(msg, lenmsg))) {
        Xmsg::log("proccessBuffer: bad CRC");
        Xmsg::printf("CRC must be 0x%x\n", crc);
        return 4;
    }

    if (msg != NULL) {
        Xmsg::printf("UDPSCANER: processed.\n");
        smsg = msg;
        static int res;
        res = this->updShmem->processBuf(smsg, lenmsg, ip);
        if (*(uint16_t*) (smsg + OFST_NLINE) == SLN_XREQSTAT) {
            Xmsg::printf("XUDPSCAN: request status\n");
            static uint16_t numXbee;
            numXbee = *(uint16_t*) (smsg + OFST_NBLOCK);
            xcont->toNewStatus(numXbee);
        }
        return res;
    } else {
        Xmsg::printf("UDPScaner: msg==NULL\n");

        return 5;
    }

}

uint16_t XUDPScaner::getLengthInPack(const char* msg) {
    return (uint16_t) ((msg[OFST_LENGTH] << 8) | msg[OFST_LENGTH + 1]) + SUM_WITHOUT_PACK;
}
